#define pragma
#include "buffer.hpp"
#include "mutex"
#include <condition_variable> //引入c++封装的条件变量
#include <atomic>
#include <thread>
#include <functional>
#include<unistd.h>
// 完成对应双buff缓冲区管理，进行异步日志输出操作

enum class AsyncIsSafe
{
    ASYNC_SAFE,
    ASYNC_UNSAFE

};
using func_t = std::function<void(Buffer &)>; // 注册进来回调函数
class Asynclooper
{

public:
    Asynclooper(func_t cb, AsyncIsSafe safe) : _safe(safe), _stop(0), _callback(cb), _thread(&Asynclooper::Threadtackle, this) {} // 全局或者静态直接传函数，类的必须要告诉是哪个对象的
    void Stop()
    {
        _stop = 1;
        _pro_con.notify_all();
        // 停止前一刻，消费者线程绝对处于条件变量阻塞中（正常）
        _con_con.notify_all();
        _thread.join();
    }
    // 生产线程往生产缓冲区写数据：
    void Push(const char *data, size_t len)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _pro_con.wait(lock, [&]()
                      { return len <= _pro_buff.Wr_size(); }); // 默认buff是安全的也就是满了就写不了了去阻塞
        _pro_buff.Push(data, len);
        // 极大可能消费者在阻塞，记得唤醒：
        _con_con.notify_all();

        //sleep(2); //通过休眠机制可以判断就是stop这里的问题（线程还没join就程序全部终止调用了它的析构释放了资源）

    }

    void Threadtackle()
    {
        while (1)
        {
            {
                std::unique_lock<std::mutex> lock(_mutex); // 生产区与消费区的活动不能同时进行(再交换缓冲区即交换时候)
                if (_stop == true && _pro_buff.Empty())
                    break; // 接到退出指令时候检查是否缓冲区还存在残留数据
                // _con_con.wait(lock, !_con_buff.Empty());   // 为真不阻塞往下走 醒来后不检查

                _con_con.wait(lock, [&]()
                              { return _stop == true || !_pro_buff.Empty(); }); // 为真不阻塞往下走,醒来后检查
             // std::cout<<"开始交换"<<std::endl;


                _con_buff.Swap(_pro_buff);
            }

            if (_safe == AsyncIsSafe::ASYNC_UNSAFE)
                _pro_con.notify_all(); // 放出阻塞的生产者线程
            _callback(_con_buff);
           // std::cout<<"回调完成"<<std::endl;
            // 进行读取日志落地的过程消费缓冲区数据不会清除
            _con_buff.Reset();
        }
    }

    ~Asynclooper() {
        Stop();//保险起见 想让他自动调停止就必须放在析构中，否则出bug
    }

private:
    AsyncIsSafe _safe = AsyncIsSafe::ASYNC_SAFE;
    std::mutex _mutex;       // 生产消费必须用一把锁（防止生产写的过程，而消费者正在进行swap）
    std::atomic<bool> _stop; // 相当于加锁（全局共享变量）确保每个线程看到都是最新的
    Buffer _pro_buff;
    Buffer _con_buff;
    std::condition_variable _pro_con;
    std::condition_variable _con_con;
    std::thread _thread; // 进行真正的日志落地输出的线程
    func_t _callback;    // 日志落地的具体函数
};